package com.xxxtea.ws;

import com.xxxtea.common.Constants;
import com.xxxtea.entity.User;
import com.xxxtea.security.AuthManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * WebSocket连接认证拦截器
 * 
 * 该拦截器在WebSocket握手阶段进行用户身份验证，确保只有已登录的用户才能建立WebSocket连接。
 * 实现了Spring WebSocket的HandshakeInterceptor接口，在握手前验证用户身份。
 * 
 * @author badman
 * @since 1.0.0
 */
@Slf4j
@Component
public class WebSocketAuthInterceptor implements HandshakeInterceptor {
	
	/**
	 * 认证管理器，用于验证用户身份
	 */
	@Resource
	private AuthManager authManager;

	/**
	 * WebSocket握手前的拦截方法
	 * 
	 * 在WebSocket连接建立之前调用，用于验证用户身份。
	 * 如果验证失败，将阻止WebSocket连接的建立。
	 * 
	 * @param request WebSocket请求对象
	 * @param response WebSocket响应对象
	 * @param wsHandler WebSocket处理器
	 * @param attributes 握手属性，用于在握手过程中传递数据
	 * @return true表示握手成功，false表示握手失败
	 */
	@Override
	public boolean beforeHandshake(@NonNull ServerHttpRequest request, @NonNull ServerHttpResponse response,
	                               @NonNull WebSocketHandler wsHandler, @NonNull Map<String, Object> attributes) {
		// 检查请求是否为ServletServerHttpRequest类型
		// 只有ServletServerHttpRequest才能获取到HttpServletRequest
		if (!(request instanceof ServletServerHttpRequest)) {
			log.warn("WebSocket请求类型不支持: {}", request.getClass().getName());
			return false;
		}
		
		try {
			// 将ServerHttpRequest转换为ServletServerHttpRequest
			ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
			// 获取原始的HttpServletRequest对象
			HttpServletRequest httpServletRequest = servletRequest.getServletRequest();
			
			// 使用认证管理器验证用户身份
			User user = authManager.verify(httpServletRequest);
			
			// 将验证后的用户信息存储到握手属性中
			// 这样在后续的WebSocket处理中就可以获取到用户信息
			attributes.put(Constants.WS_USER_KEY, user);
			
			log.debug("WebSocket用户认证成功: userId={}", user.getId());
			
		} catch (Exception e) {
			// 记录认证失败的错误日志
			log.error("WebSocket登录失败", e);
			return false;
		}
		
		return true;
	}

	/**
	 * WebSocket握手后的回调方法
	 * 
	 * 在WebSocket握手完成后调用，通常用于清理资源或记录日志。
	 * 当前实现为空，可根据需要添加相关逻辑。
	 * 
	 * @param request WebSocket请求对象
	 * @param response WebSocket响应对象
	 * @param wsHandler WebSocket处理器
	 * @param exception 握手过程中发生的异常，如果握手成功则为null
	 */
	@Override
	public void afterHandshake(@NonNull ServerHttpRequest request, @NonNull ServerHttpResponse response,
	                           @NonNull WebSocketHandler wsHandler, Exception exception) {
		// 握手后的处理逻辑，当前为空实现
		// 可以在这里添加握手成功后的日志记录或其他处理逻辑
		if (exception != null) {
			log.error("WebSocket握手后发生异常", exception);
		} else {
			log.debug("WebSocket握手完成");
		}
	}
}